//
//  GCHelper.m
//  Game Center
//
//  Created by admin on 3/28/12.
//  Copyright (c) 2012 __MyCompanyName__. All rights reserved.
//

#import "GCHelper.h"

@implementation GCHelper
@synthesize gameCenterAvailable;

@synthesize presentingViewController;
@synthesize match;
@synthesize delegate;
@synthesize playersDict;
@synthesize achievementsDictionary;
@synthesize pendingInvite;
@synthesize pendingPlayersToInvite;



#pragma mark Initialization

static GCHelper *sharedHelper = nil;
+ (GCHelper *) sharedInstance {
    if (!sharedHelper) {
        sharedHelper = [[GCHelper alloc] init];
    }
    return sharedHelper;
}
- (BOOL)isGameCenterAvailable {
    // check for presence of GKLocalPlayer API
    Class gcClass = (NSClassFromString(@"GKLocalPlayer"));
    
    // check if the device is running iOS 4.1 or later
    NSString *reqSysVer = @"4.1";
    NSString *currSysVer = [[UIDevice currentDevice] systemVersion];
    BOOL osVersionSupported = ([currSysVer compare:reqSysVer 
                                           options:NSNumericSearch] != NSOrderedAscending);
    
    return (gcClass && osVersionSupported);
}
- (id)init {
    if ((self = [super init])) {
        gameCenterAvailable = [self isGameCenterAvailable];
        if (gameCenterAvailable) {
            NSNotificationCenter *nc = 
            [NSNotificationCenter defaultCenter];
            [nc addObserver:self 
                   selector:@selector(authenticationChanged) 
                       name:GKPlayerAuthenticationDidChangeNotificationName 
                     object:nil];
        }
    }
    return self;
}

- (void)authenticationChanged {    
    
    if ([GKLocalPlayer localPlayer].isAuthenticated && !userAuthenticated) {
        NSLog(@"Authentication changed: player authenticated.");
        userAuthenticated = TRUE;  
        
        [GKMatchmaker sharedMatchmaker].inviteHandler = ^(GKInvite *acceptedInvite, NSArray *playersToInvite) {
            
            NSLog(@"Received invite");
            self.pendingInvite = acceptedInvite;
            self.pendingPlayersToInvite = playersToInvite;
            [delegate inviteReceived];
            
        };
    } else if (![GKLocalPlayer localPlayer].isAuthenticated && userAuthenticated) {
        NSLog(@"Authentication changed: player not authenticated");
        userAuthenticated = FALSE;
    }
    
}

- (void)lookupPlayers{
    NSLog(@"Looking up %d players...",match.playerIDs.count);
    [GKPlayer loadPlayersForIdentifiers:match.playerIDs
                  withCompletionHandler:^(NSArray *players, NSError *error) {
                     if(error != nil)
                     {
                         NSLog(@"Error retieving player info: %@",error.localizedDescription);
                         matchStarted = NO;
                         [delegate matchEnded];
                     }else
                     {
                         // Populate players dict
                         self.playersDict = [NSMutableDictionary dictionaryWithCapacity:players.count];
                         for(GKPlayer* player in players)
                         {
                             NSLog(@"Found player: %@", player.alias);
                             [playersDict setObject:player forKey:player.playerID];
                         }
                         
                         // Notify delegate match can begin
                         matchStarted = YES;
                         [delegate matchStarted];
                     }
                  }];
}
#pragma mark User functions

- (void)authenticateLocalUser { 
    
    if (!gameCenterAvailable) return;
    
    NSLog(@"Authenticating local user...");
    if ([GKLocalPlayer localPlayer].authenticated == NO) {     
        [[GKLocalPlayer localPlayer] authenticateWithCompletionHandler:^(NSError *error){
            if(error)
            {
                NSLog(@"Autheticate Player error: %@",error);
            }
        }];        
    } else {
        NSLog(@"Already authenticated!");
    }
}

- (void)findMathWithMinPlayers:(int)minPlayers 
                    maxPlayers:(int)maxPlayers 
                viewController:(UIViewController*)viewController 
                      delegate:(id<GCHelperDelegate>) theDelegate
{
    if(!gameCenterAvailable)
        return;
    matchStarted = NO;
    self.match = nil;
    self.presentingViewController = viewController;
    delegate = theDelegate;
    
    if(pendingInvite != nil)
    {
        [presentingViewController dismissModalViewControllerAnimated:NO];
        GKMatchmakerViewController* mmvc = [[GKMatchmakerViewController alloc] initWithInvite:pendingInvite];
        
        mmvc.matchmakerDelegate = self;
        [presentingViewController presentModalViewController:mmvc animated:YES];
        
        self.pendingInvite = nil;
        self.pendingPlayersToInvite = nil;
    }else
    {
        [presentingViewController dismissModalViewControllerAnimated:NO];
        
        GKMatchRequest* request = [[[GKMatchRequest alloc] init] autorelease];
        request.minPlayers = minPlayers;
        request.maxPlayers = maxPlayers;
        request.playersToInvite = pendingPlayersToInvite;
        
        GKMatchmakerViewController* mmvc = [[[GKMatchmakerViewController alloc] initWithMatchRequest:request] autorelease];
        mmvc.matchmakerDelegate = self;
        
        [presentingViewController presentModalViewController:mmvc animated:YES];
        
        self.pendingInvite = nil;
        self.pendingPlayersToInvite = nil;
    }
    

}

- (void) reportScore: (int64_t) score forCategory: (NSString*) category 
{
    NSLog(@">>>>>>>>>>>>reportScore: %lld forCategory: %@ >>>>>>>>>>>>",score, category);
	GKScore *scoreReporter = [[[GKScore alloc] initWithCategory:category] autorelease];	
	scoreReporter.value = score;
	[scoreReporter reportScoreWithCompletionHandler: ^(NSError *error) 
	 {
         assert([NSThread isMainThread]);
         dispatch_async(dispatch_get_main_queue(), ^(void)
                        {
                            [self.delegate scoreReported:error];
                        });
         
	 }];

}
- (void) reloadHighScoresForCategory: (NSString*) category
{
	GKLeaderboard* leaderBoard= [[[GKLeaderboard alloc] init] autorelease];
	leaderBoard.category= category;
	leaderBoard.timeScope= GKLeaderboardTimeScopeAllTime;
	leaderBoard.range= NSMakeRange(1, 1);
    
    GKScore* myScore = [leaderBoard localPlayerScore];
    NSLog(@">>>>>>>>>myScore>>>>>>>>>%lld",myScore.value);
	
	[leaderBoard loadScoresWithCompletionHandler:  ^(NSArray *scores, NSError *error)
     {
         assert([NSThread isMainThread]);
         dispatch_async(dispatch_get_main_queue(), ^(void)
                        {
                            [self.delegate reloadScoresComplete:leaderBoard error:error];
                        });
         
     }];
}

- (void)loadAchievements
{    
    [GKAchievement loadAchievementsWithCompletionHandler:^(NSArray *achievements, NSError *error) {
        if (error != nil)
        {
            // handle errors
        }
        if (achievements != nil)
        {
            // process array of achievements
            achievementsDictionary = [[NSMutableDictionary alloc] initWithCapacity:[achievements count]];
            
            for (GKAchievement* achievement in achievements){
                NSLog(@">>>>>>%d>>>>>>>>>>>achievement.percentComplete>>>>>>>>>>>>>>>>>%f",[achievements count],achievement.percentComplete);
                [achievementsDictionary setObject:achievement forKey:achievement.identifier];
            }
        }
    }];
}

/**
 * Get an achievement object in the locally stored dictionary
 */
- (GKAchievement *)getAchievementForIdentifier:(NSString *)identifier
{
    
    GKAchievement *achievement = [achievementsDictionary objectForKey:identifier];
    if (achievement == nil)
    {
        achievement = [[[GKAchievement alloc] initWithIdentifier:identifier] autorelease];
        [achievementsDictionary setObject:achievement forKey:achievement.identifier];
    }
    return [[achievement retain] autorelease];
	
	return nil;
}

/**
 * Send a completion % for a specific achievement to Game Center
 */
- (void)reportAchievementIdentifier:(NSString *)identifier percentComplete:(float)percent
{
    
    // Instantiate GKAchievement object for an achievement (set up in iTunes Connect)
    GKAchievement *achievement = [self getAchievementForIdentifier:identifier];
    if (achievement)
    {
        achievement.percentComplete = percent;
        [achievement reportAchievementWithCompletionHandler:^(NSError *error)
         {
             assert([NSThread isMainThread]);
             dispatch_async(dispatch_get_main_queue(), ^(void)
                            {
                                [self.delegate submitAchievementsComplete:achievement error:error];
                            });

         }];
    }
}

/**
 * Send a completion % for a specific achievement to Game Center - increments an existing achievement object
 */
- (void)reportAchievementIdentifier:(NSString *)identifier incrementPercentComplete:(float)percent
{
    
    GKAchievement *achievement = [self getAchievementForIdentifier:identifier];
    if (achievement)
    {
        achievement.percentComplete += percent;
        [achievement reportAchievementWithCompletionHandler:^(NSError *error)
         {
             assert([NSThread isMainThread]);
             dispatch_async(dispatch_get_main_queue(), ^(void)
                            {
                                [self.delegate submitAchievementsComplete:achievement error:error];
                            });
         }];
    }
	
}

-(void)getCurrentLeaderboardScore:(NSString *)Category withCalculatedScore:(int)calculatedScore
{
    //NSLog(@"find score for category %@ ", Category);
    if([GKLocalPlayer localPlayer].authenticated) {
        NSArray *arr = [[NSArray alloc] initWithObjects:[GKLocalPlayer localPlayer].playerID, nil];
        GKLeaderboard *board = [[GKLeaderboard alloc] initWithPlayerIDs:arr];
        if(board != nil) {
            board.timeScope = GKLeaderboardTimeScopeAllTime;
            board.range = NSMakeRange(1, 1);
            board.category = Category;
            [board loadScoresWithCompletionHandler: ^(NSArray *scores, NSError *error) {
                if (error != nil) {
                    // handle the error.
                    NSLog(@"Error retrieving score. %@",error);
                }
                if (scores != nil) {
                    int myCurrScore = ((GKScore*)[scores objectAtIndex:0]).value;
                    NSLog(@"My Score: %i", myCurrScore);
                    int totalScoreToSubmit = myCurrScore+calculatedScore;
                    [[GCHelper sharedInstance] reportScore:totalScoreToSubmit forCategory:Category];
                }
            }];
        }
        [board release];
        [arr release];
    }
}

#pragma mark GKMatchmakerViewControllerDelegate
- (void)matchmakerViewControllerWasCancelled:(GKMatchmakerViewController *)viewController{
    [presentingViewController dismissModalViewControllerAnimated:YES];
}

- (void)matchmakerViewController:(GKMatchmakerViewController *)viewController 
                didFailWithError:(NSError *)error{
    [presentingViewController dismissModalViewControllerAnimated:YES];
    NSLog(@"Error finding match: %@", error.localizedDescription);
}
- (void)matchmakerViewController:(GKMatchmakerViewController *)viewController didFindMatch:(GKMatch *)thematch
{
    [presentingViewController dismissModalViewControllerAnimated:YES];
    self.match = thematch;
    match.delegate = self;
    if(!matchStarted && match.expectedPlayerCount == 0)
    {
        NSLog(@"Ready to start match 1!");
        [self lookupPlayers];
    }
}

#pragma mark GKMatchDelegate
- (void)match:(GKMatch *)thematch didReceiveData:(NSData *)data 
   fromPlayer:(NSString *)playerID{
    if(match != thematch)
    {
        return;
    }
    [delegate match:thematch didReceiveData:data fromPlayer:playerID];
}

- (void)match:(GKMatch *)thematch player:(NSString *)playerID didChangeState:(GKPlayerConnectionState)state
{
    if(match != thematch)
    {
        return;
    }
    
    switch (state) {
        case GKPlayerStateConnected:
            NSLog(@"Player connected!");
            if(!matchStarted && thematch.expectedPlayerCount == 0)
            {
                NSLog(@"Ready to start match 2!");
                [self lookupPlayers];
            }
            break;
            
        case GKPlayerStateDisconnected:
            NSLog(@"Player disconected");
            matchStarted = NO;
            [delegate matchEnded];
            break;
        default:
            break;
    }
}

-(void)match:(GKMatch *)thematch connectionWithPlayerFailed:(NSString *)playerID withError:(NSError *)error
{
    if(match != thematch)
    {
        return;
    }
    
    NSLog(@"Failed to connect to player with error: %@", error.localizedDescription);
    matchStarted = NO;
    [delegate matchEnded];
}

- (void)match:(GKMatch *)thematch didFailWithError:(NSError *)error
{
    if(match != thematch)
    {
        return;
    }
    
    NSLog(@"Failed to connect to player with error: %@", error.localizedDescription);
    matchStarted = NO;
    [delegate matchEnded];
}



@end
